package cn.cagurzhan.service;

import cn.cagurzhan.common.constant.*;
import cn.cagurzhan.common.exception.ServiceException;
import cn.cagurzhan.domain.BaseEntity;
import cn.cagurzhan.domain.R;
import cn.cagurzhan.domain.dto.CommandResultDto;
import cn.cagurzhan.domain.entity.HomeLog;
import cn.cagurzhan.domain.entity.OperLog;
import cn.cagurzhan.domain.entity.User;
import cn.cagurzhan.domain.event.HomeLogEvent;
import cn.cagurzhan.domain.vo.SafetyVo;
import cn.cagurzhan.domain.vo.ShouyeVo;
import cn.cagurzhan.mapper.HomeLogMapper;
import cn.cagurzhan.mapper.OperLogMapper;
import cn.cagurzhan.mapper.UserMapper;
import cn.cagurzhan.utils.AppJwtUtil;
import cn.cagurzhan.utils.BeanCopyUtils;
import cn.cagurzhan.utils.ServletUtils;
import cn.cagurzhan.utils.spring.SpringUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.roma.v2.model.Command;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.PathVariable;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author AjaxZhan
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CommandService {
    // private static final String DEVICE_ID_HOME = "65ed96477bdccc0126c79cb0_ESP32_WROOM";
    private static final String DEVICE_ID_HOME = "65ed96477bdccc0126c79cb0_0001";

    private final IoTService ioTService;

    private final CacheService cacheService;

    private final HomeLogMapper homeLogMapper;

    private final UserMapper userMapper;

    private final OperLogMapper operLogMapper;

    /**
     * 功能：【获取】首页信息
     * 描述：直接从华为云拿到设备影子，封装后返回
     */
    public R<ShouyeVo> getShouyeInfo(){
        // 拿到设备影子
        IoTDAClient client = ioTService.initClient();
        Map<String, Object> deviceShadowProperties = ioTService.getDeviceShadowProperties(client, DEVICE_ID_HOME);
        log.info("远程调用：{}，拿到设备影子：{}","getShouyeInfo", JSON.toJSONString(deviceShadowProperties));
        // 封装
        ShouyeVo vo = JSON.parseObject(JSON.toJSONString(deviceShadowProperties), ShouyeVo.class);
        return R.ok(vo);
    }

    /**
     * 功能：【获取】安全页面信息
     * 描述：从Redis获取房间状态数据后返回。
     */
    public R<HomeLog> getSafetyVo(){
        HomeLog homeLog = null;
        if(!cacheService.exists(CacheConstants.HOME)){
            // 如果Redis中没有数据，从数据库拿到最新记录
            LambdaQueryWrapper<HomeLog> wrapper = new LambdaQueryWrapper<>();
            wrapper.orderByDesc(HomeLog::getLogTime);
            homeLog = homeLogMapper.selectList(wrapper).get(0);
            // 写入缓存
            cacheService.setEx(CacheConstants.HOME,JSON.toJSONString(homeLog),60, TimeUnit.MINUTES);
        }else {
            // 从Redis中获取数据
            String json = cacheService.get(CacheConstants.HOME);
            homeLog  = JSON.parseObject(json, HomeLog.class);
        }
        log.info("请求地址：{}，返回值如下：{}","getSafetyVo",JSON.toJSONString(homeLog));
        return R.ok(homeLog);
    }

    private void doorOpenWithoutLog(Integer status){
        IoTDAClient client = ioTService.initClient();
        // 构造请求参数
        HashMap<String, Object> params = new HashMap<>();
        if(status == 1){
            params.put(CommandNameConstants.DOOR_OPEN_PARAMS, CommandPropertiesConstants.OPEN_DOOR);
        }else{
            params.put(CommandNameConstants.DOOR_OPEN_PARAMS,CommandPropertiesConstants.CLOSE_DOOR);
        }
        // 发送请求
        CommandResultDto commandResultDto = ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL, CommandNameConstants.DOOR_OPEN, params);
        log.info("远程调用：{}，得到返回值：{}","doorOpen",JSON.toJSONString(commandResultDto));
    }

    /**
     * 指令：开门
     * @param status 0关门 1开门
     */
    public R<Void> doorOpen(Integer status){
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setGateState(status);

        doorOpenWithoutLog(status);

        if(status == 1){
            homeLogEvent.setType("打开大门");
        }else{
            homeLogEvent.setType("关闭大门");
        }
        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 指令：打开车库门
     * @param status 0关门 1开门
     */
    public R<Void> carDoorOpen(Integer status){
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setCarDoorState(status);

        IoTDAClient client = ioTService.initClient();

        HashMap<String, Object> params = new HashMap<>();
        if(status == 1){
            params.put(CommandNameConstants.CAR_DOOR_OPEN_PARAMS,CommandPropertiesConstants.CAR_DOOR_OPEN);
            homeLogEvent.setType("打开车库门");
        }else{
            params.put(CommandNameConstants.CAR_DOOR_OPEN_PARAMS,CommandPropertiesConstants.CAR_DOOR_CLOSE);
            homeLogEvent.setType("关闭车库门");
        }

        CommandResultDto commandResultDto = ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                CommandNameConstants.CAR_DOOR_OPEN, params);
        log.info("请求地址：[/car_door_open]得到返回值：{}",JSON.toJSONString(commandResultDto));

        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 【暂时不用，没加日志】指令：车库内门
     * @param status 0关门 1开门
     */
    public R<Void> caridoor(Integer status){
        IoTDAClient client = ioTService.initClient();
        HashMap<String, Object> params = new HashMap<>();
        if(status == 1){
            params.put(CommandNameConstants.CARIDOOR_PARAMS,CommandPropertiesConstants.OPEN_DOOR);
        }else{
            params.put(CommandNameConstants.CARIDOOR_PARAMS,CommandPropertiesConstants.CLOSE_DOOR);
        }

        CommandResultDto commandResultDto = ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                CommandNameConstants.CARIDOOR, params);
        log.info("请求地址：[/Caridoor]得到返回值：{}",JSON.toJSONString(commandResultDto));
        return R.ok();
    }

    /**
     * 更新【HomeLog】，插入【OperLog】
     */
    private void recordOpLog(HomeLogEvent homeLogEvent) {
        // 获取用户ID
        String userId = ServletUtils.getRequest().getHeader("user-id");
        log.warn("正在记录操作日志, userId={}", userId);
        User user = null;
        if (userId != null) {
            // 查询用户
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.select(User::getNickname).eq(User::getUserId, Long.valueOf(userId));
            user = userMapper.selectById(Long.valueOf(userId));
        } else {
            user = new User();
            user.setNickname("系统用户");
        }
        // 更新HomeLog
        HomeLog homeLog = new HomeLog();
        BeanCopyUtils.copy(homeLogEvent, homeLog);
        homeLog.setLogId(1L);
        homeLog.setLogBy(user.getNickname());
        homeLogMapper.updateById(homeLog);
        cacheService.setEx(CacheConstants.HOME, JSON.toJSONString(homeLog), 60, TimeUnit.MINUTES);
        // 新增操作日志
        OperLog operLog = new OperLog();
        operLog.setLogBy(user.getNickname());
        operLog.setType(homeLogEvent.getType());
        operLog.setDelFlag(0);
        operLogMapper.insert(operLog);
    }

    /**
     * 控制窗户角度
     */
    public R<Void> windowControl(Integer angle) {
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setWindowState(angle);
        IoTDAClient client = ioTService.initClient();
        HashMap<String, Object> params = new HashMap<>();
        if(angle == 0){
            // 关闭
            params.put(CommandNameConstants.WINDOW_CONTROL_PARAMS_ANGLE,170);
            homeLogEvent.setType("关闭窗户");
        }else{
            // 开启
            params.put(CommandNameConstants.WINDOW_CONTROL_PARAMS_ANGLE,90);
            homeLogEvent.setType("开启窗户");
        }
        // 远程调用
        CommandResultDto commandResultDto =
                ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                CommandNameConstants.WINDOW_CONTROL, params);
        log.info("命令：{}，得到返回值：{}",CommandNameConstants.WINDOW_CONTROL,JSON.toJSONString(commandResultDto));
        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 控制LED
     * @param which 哪个灯
     * @param light 亮度
     */
    public R<Void> ledControl(Integer which, Integer light) {
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setType("设置灯光:"+which + " 亮度为"+light);
        IoTDAClient client = ioTService.initClient();
        HashMap<String, Object> params = new HashMap<>();
        params.put(CommandNameConstants.LED_CONTROL_PARAMS_CHOOSE,which);
        params.put(CommandNameConstants.LED_CONTROL_PARAMS_PWM,light);

        // 远程调用
        CommandResultDto commandResultDto =
                ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                        CommandNameConstants.LED_CONTROL, params);
        log.info("命令：{}，得到返回值：{}",CommandNameConstants.LED_CONTROL,JSON.toJSONString(commandResultDto));

        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 返回所有日志消息
     */
    public R<List<OperLog>> listLog() {
        LambdaQueryWrapper<OperLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(BaseEntity::getLogTime);
        wrapper.last("LIMIT 30");
        return R.ok(operLogMapper.selectList(wrapper));
    }


    /**
     * 报警
     */
    public R<Void> alarm(Integer status) {
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setType("警报状态" + (status == 0 ? "开启": "关闭"));
        homeLogEvent.setFireAlarm(status);
        IoTDAClient client = ioTService.initClient();
        HashMap<String, Object> params = new HashMap<>();
        params.put("fg_alarm",status);

        // 远程调用
        CommandResultDto commandResultDto =
                ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                        "alarm", params);
        log.info("命令：{}，得到返回值：{}","alarm",JSON.toJSONString(commandResultDto));

        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 模式修改
     */
    public R<Void> changeHomeStatus(Integer status) {
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setType("智慧家居模式设置" + status);
        homeLogEvent.setHomeStatus(status);
        IoTDAClient client = ioTService.initClient();
        HashMap<String, Object> params = new HashMap<>();
        params.put("mode",status);

        // 远程调用
        CommandResultDto commandResultDto =
                ioTService.sendCommand(client, DEVICE_ID_HOME, ServiceConstant.MACHINE_CONTROL,
                        "mode_control", params);
        log.info("命令：{}，得到返回值：{}","mode_control",JSON.toJSONString(commandResultDto));

        // 记录日志
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 指纹开门，记录日志
     */
    public R<Void> finger(Map<String, Object> properties) {
        Integer who = (Integer) properties.get("who");
        Boolean emergy = (Boolean) properties.get("Emergy");
        // 记录日志
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        doorOpenWithoutLog(1);
        if(emergy){
            // 报警
            alarm(0);
            homeLogEvent.setType("用户" + MapConstant.ZHIWEN[who] + "紧急指纹开门");
        }else{
            homeLogEvent.setType("用户" + MapConstant.ZHIWEN[who] + "使用指纹开门");
        }
        recordOpLog(homeLogEvent);
        return R.ok();
    }

    /**
     * 人脸识别开门
     */
    public R<Void> face(Map<String, Object> properties) {
        Integer who = (Integer) properties.get("face_name");
        // 记录日志
        HomeLogEvent homeLogEvent = new HomeLogEvent();
        homeLogEvent.setType("用户" + MapConstant.RENLIAN[who] + "通过人脸识别开门");
        doorOpenWithoutLog(1);
        recordOpLog(homeLogEvent);
        return R.ok();
    }
}
